package fybug.nulll.pdstream.WR.Parsing;
import com.sun.istack.internal.NotNull;
import com.sun.istack.internal.Nullable;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;

import fybug.nulll.pdfunctionlibrary.Processing.Check;
import fybug.nulll.pdfunctionlibrary.Processing.Err.Stop;
import fybug.nulll.pdstream.WR.Err.CharStreamErr;
import fybug.nulll.pdstream.WR.Parsing.Interface.StringResolve;
import fybug.nulll.pdstream.WR.Parsing.Source.ParsingSource;
import fybug.nulll.pdstream.WR.Parsing.Source.Partition.ParsingPartition;

import static fybug.nulll.pdstream.StreamOperator.toBufferStream;
/**
 * {@link StringParsingBoot}
 *
 * @author fybug
 * @version 0.1.0
 * @see StringParsingS
 * @see StringParsingBoot
 * @since JDK 1.8
 */
@SuppressWarnings( "all" )
class StringParsing extends StringParsingBoot {
    // 解析源
    @Nullable private ParsingSource[] stringSoure = new ParsingSource[1];

    /** <p>构造一个空解析器.</p> */
    StringParsing() {this(null);}

    /** <p>根据输入的解析源构造解析器.</p> */
    StringParsing(@Nullable final ParsingSource soure) { binSoure(soure); }

    /**
     * <p>对比内部字段是否一致.</p>
     * <pre>
     * 用于检查其中的变量是否相同
     * 应在检查类型和空对象后调用
     * </pre>
     */
    protected
    boolean consistent(@NotNull final Object obj) {
        @NotNull final StringParsing parsing = (StringParsing) obj;
        // 检查源
        return Check.equalsArrayTable(stringSoure, parsing.stringSoure);
    }

    /*
     * Soure
     */

    @NotNull
    @Override
    public final
    StringParsing binSoure(@Nullable final ParsingSource soure) {
        try {
            synchronized ( this ){
                Check.checkNull(this.stringSoure)[0] = soure;
            }
        } catch ( Stop ignored ) {
        }
        return this;
    }

    @NotNull
    @Override
    public
    ParsingSource soure() { return Check.checkArrayTable(stringSoure); }

    @Override
    @NotNull
    public
    StringParsingBoot binReader(@NotNull final Reader reader) {
        try {
            soure().binreader(toBufferStream(reader, 8192));
        } catch ( Stop ignored ) {
        }
        return this;
    }

    @Override
    @NotNull
    public
    StringParsingBoot binReader(@NotNull final InputStream inputStream) {
        try {
            soure().binreader(toBufferStream(new InputStreamReader(inputStream), 8192));
        } catch ( Stop ignored ) {
        }
        return this;
    }

    @Override
    @NotNull
    public
    StringParsingBoot binReader(@NotNull final CharSequence charSequence) {
        try {
            soure().binreader(new StringReader(charSequence.toString()));
        } catch ( Stop ignored ) {
        }
        return this;
    }

    @Override
    @NotNull
    public
    StringParsingBoot binPartition(@NotNull final ParsingPartition r) {
        try {
            soure().binPartition(r);
        } catch ( Stop ignored ) {
        }
        return this;
    }

    /*
     * 解析
     */

    @NotNull
    @Override
    public
    StringParsing parsing(@Nullable final StringResolve resolve) throws CharStreamErr {
        // 没有解析源
        if (resolve == null)
            return this;
        // 解析次数
        long number = 0;
        @NotNull ParsingSource soure;
        try {
            soure = Check.checkArrayTable(this.stringSoure);
            synchronized ( soure ){
                resolve.init();
                // 保证对象锁
                while( soure.readly() ){
                    // 调用接口解析
                    resolve.resolve(soure.read());
                    number++;
                    // 返回解析进度
                    resolve.progress(number);
                }
                soure = null;
                number = 0;
            }
        } catch ( Stop ignored ) {
        } finally {
            resolve.destroy();
        }
        return this;
    }

    /*
     * 释放
     */

    @Override
    public
    void clean() { binSoure(null); }

    @Override
    public
    void free() {
        try {
            @NotNull final ParsingSource soure = Check.checkArrayTable(this.stringSoure);
            synchronized ( soure ){
                soure.close();
            }
        } catch ( Throwable ignored ) {
        }
        clean();
    }

    @Override
    public
    void close() {
        free();
        synchronized ( this ){
            stringSoure = null;
        }
    }
}
